﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Gunningine
{
    namespace Rendersystems
    {
        namespace OpenGL
        {
            using OpenTK;
            using OpenTK.Graphics;
            using OpenTK.Graphics.OpenGL;
            using Gunningine;

            internal class ShaderGL : Shader, IDisposable
            {
                private int vertexShaderId;

                private int fragmentShaderId;

                /// <summary>
                /// Constructor.
                /// </summary>
                /// <param name="vertexShader"></param>
                /// <param name="fragmentShader"></param>
                public ShaderGL(TextResource vertexShader, TextResource fragmentShader)
                    : base(vertexShader, fragmentShader)
                {
                    this.vertexShaderId = CreateShader(ShaderType.VertexShader, vertexShader);
                    this.fragmentShaderId = CreateShader(ShaderType.FragmentShader, fragmentShader);

                    this.Id = GL.CreateProgram();
                    GL.AttachShader(this.Id, this.vertexShaderId);
                    GL.AttachShader(this.Id, this.fragmentShaderId);
                    GL.LinkProgram(this.Id);
                }

                /// <summary>
                /// Destructor.
                /// </summary>
                ~ShaderGL()
                {
                    Dispose();
                }

                /// <summary>
                /// Compile a shader.
                /// </summary>
                /// <param name="type"></param>
                /// <param name="src"></param>
                /// <returns></returns>
                private int CreateShader(ShaderType type, TextResource src)
                {
                    int id = GL.CreateShader(type);

                    GL.ShaderSource(id, src.Text);
                    GL.CompileShader(id);

                    int compileStatus;
                    GL.GetShader(id, ShaderParameter.CompileStatus, out compileStatus);
                    if (compileStatus != 1)
                    {
                        string infoLog = GL.GetShaderInfoLog(id);
                        string errMsg = String.Format("There were errors compiling {0}: {1}", src.Filename, infoLog);
                        throw new Exception(errMsg);
                    }

                    return id;
                }

                /// <summary>
                /// Activate shader.
                /// </summary>
                public override void Activate()
                {
                    GL.UseProgram(this.Id);
                }

                /// <summary>
                /// Deactivate shader.
                /// </summary>
                public override void Deactivate()
                {
                    GL.UseProgram(0);
                }

                /// <summary>
                /// Get the location of a named uniform variable.
                /// </summary>
                /// <returns></returns>
                public override int GetUniformLocation(string name)
                {
                    return GL.GetUniformLocation(this.Id, name);
                }

                /// <summary>
                /// Set shader uniform.
                /// </summary>
                /// <param name="name"></param>
                /// <param name="value"></param>
                public override void SetValueUniform(string name, int value)
                {
                    GL.Uniform1(GetUniformLocation(name), value);
                }

                /// <summary>
                /// Set shader uniform.
                /// </summary>
                /// <param name="name"></param>
                /// <param name="value"></param>
                public override void SetValueUniform(string name, float value)
                {
                    GL.Uniform1(GetUniformLocation(name), value);
                }

                /// <summary>
                /// Set shader uniform.
                /// </summary>
                /// <param name="name"></param>
                /// <param name="value"></param>
                public override void SetValueUniform(string name, Gunningine.Vector2 value)
                {
                    GL.Uniform2(GetUniformLocation(name), value.X, value.Y);
                }

                /// <summary>
                /// Dispose.
                /// </summary>
                protected override void DisposeImpl()
                {
                    //GL.DeleteProgram(this.Id);
                }
            }
        }
    }
}
